// ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! 
//
// Devenger - If I'm not responding/offline, feel free to spruce this up (it's ugly)
//
// ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! 

local defaultHealthMultiplier = 3

local models = {
	[ "models/props_lab/blastdoor001a.mdl" ] = {
		Cost = 100
	},
	[ "models/props_lab/blastdoor001b.mdl" ] = {
		Cost = 100
	},
	[ "models/props_lab/blastdoor001c.mdl" ] = {
		Cost = 200
	},
	[ "models/props_c17/oildrum001.mdl" ] = {
		Cost = 50
	},
	[ "models/props_c17/door01_left.mdl" ] = {
		Cost = 150,
		AddV = Vector( 0, 0, 64 )
	},
	[ "models/props_interiors/VendingMachineSoda01a_door.mdl" ] = {
		Cost = 200,
		AddV = Vector( 0, 0, 64 )
	},
	[ "models/props_trainstation/trainstation_clock001.mdl" ] = {
		Cost = 50,
		AddV = Vector( 0, 0, 32 )
	},
	[ "models/props_building_details/Storefront_Template001a_Bars.mdl" ] = {
		Cost = 200,
		AddV = Vector( 0, 0, 64 )
	},
	[ "models/props_c17/concrete_barrier001a.mdl" ] = {
		Cost = 150
	},
	[ "models/props_c17/display_cooler01a.mdl" ] = {
		Cost = 100
	},
	[ "models/props_c17/FurnitureBed001a.mdl" ] = {
		Cost = 100,
		Vector( 0, 0, 32 )
	},
	[ "models/props_wasteland/wood_fence01a.mdl" ] = {
		Cost = 50,
		Health = 300,
		Ignitable = true,
		AddV = Vector( 0, 0, 64 )
	},
	[ "models/props_wasteland/wood_fence02a.mdl" ] = {
		Cost = 25,
		Health = 150,
		Ignitable = true,
		AddV = Vector( 0, 0, 64 )
	},
	[ "models/props_junk/wood_crate001a.mdl" ] = {
		Cost = 25,
		Health = 150,
		Ignitable = true,
		AddV = Vector( 0, 0, 16 )
	},
	[ "models/props_junk/wood_crate002a.mdl" ] = {
		Cost = 50,
		Health = 300,
		Ignitable = true,
		AddV = Vector( 0, 0, 16 )
	},
	[ "models/props_c17/shelfunit01a.mdl" ] = {
		Cost = 75,
		Health = 450,
		Ignitable = true
	},
	[ "models/props_junk/wood_pallet001a.mdl" ] = {
		Cost = 25,
		Health = 150,
		Ignitable = true
	}		
}

local entities = {
	[ "inc_charger_health" ] = {
		Name = "Health Charger",
		Model = "models/props_combine/suit_charger001.mdl",
		Cost = 1000,
		AddNormal = 0,
		SetAngles = function( e, p, t ) e:SetAngles( t.HitNormal:Angle() ) end,
		Repairable = true,
		ShouldTakeDamage = true,
		Health = 750,
		BlowUp = false
	},
	[ "inc_armory" ] = {
		Name = "Equipment Armory",
		Model = "models/items/ammocrate_smg1.mdl",
		Cost = 1000,
		AddNormal = 16.5,
		Repairable = true,
		ShouldTakeDamage = true,
		Health = 1000,
		BlowUp = true
	}
}

local categories = {
	{
		"Props",
		function( p )
			for model, info in pairs( models ) do
				p:AddIcon( model, { "inc_spawn", model },
					"Cost: " .. ( info.Cost or info.Health ) .. "\nHealth: " .. ( info.Health or ( info.Cost * defaultHealthMultiplier ) )
				)
			end
		end
	},
	{
		"Supplies",
		function( p )
			for entity, info in pairs( entities ) do
				p:AddIcon( info.Model or "", { "inc_spawnentity", entity }, ( info.Name or entity ) .. "\nCost: " .. ( info.Cost or 0 ) )
			end
		end
	}
}

if ( SERVER ) then

	function GM:SpawnProp( ply, _, args )
		if ( !self:IsBuild() ) then return end
		
		local model = args[ 1 ]
		if ( !util.IsValidModel( model ) ) then return end
		
		if ( !models[ model ] ) then return end
		local info = models[ model ]
		info.Ignitable = info.Ignitable or false
		
		if ( !self:SpendCredits( ply, info.Cost or info.Health ) ) then return end
		
		local trace = util.QuickTrace( ply:GetShootPos(), ply:GetAimVector() * 8192, ply )
		
		local angle = ply:EyeAngles()
			angle.p, angle.y, angle.r = 0, angle.y + 180, 0
			
		local prop = ents.Create( "prop_physics" )
			prop:SetModel( model )
			prop:SetPos( trace.HitPos + ( trace.HitNormal * ( info.AddNormal or 16 ) ) + ( info.AddV or Vector( 0, 0, 0 ) ) )
			prop:SetAngles( angle )
			
			local health = ( info.Health or info.Cost ) * defaultHealthMultiplier
			self:SetPropHealth( prop, health )
			self:SetPropMaxHealth( prop, health )

			prop.Player = ply:UniqueID()
			prop.Ignitable = info.Ignitable
			prop.CanPhysgunPickup = true
			prop.Repairable = true
			prop.ShouldTakeDamage = true
			prop.Cost = info.Cost or info.Health
			prop.BlowUp = true
			prop.FreezeOnFight = true
		prop:Spawn()
		prop:SetHealth( 9999 ) // We don't want it do get blown up normally!
		
		local phys = prop:GetPhysicsObject()
		if ( phys:IsValid() ) then
			phys:Wake()
			phys:SetVelocity( Vector( 0, 0, -1 ) )
			timer.Simple( 0.1, function()
				if ( phys:IsPenetrating() ) then
					prop:Remove()
					self:GiveCredits( ply, info.Cost or info.Health )
				end
			end )
		end
		
		--npc_bullseye
		local bull = ents.Create ("npc_bullseye")
		bull:SetPos (prop:LocalToWorld (prop:OBBCenter()))
		bull:SetParent (prop)
		bull:SetKeyValue ("spawnflags", 65536 + 131072) --non-solid, no damage
		bull:Spawn()
		bull:SetName ("prop_bullseye")
		
		// Prop protection, bitches?
		hook.Call( "PlayerSpawnedProp", self, ply, model, prop )
		cleanup.Add( ply, "", prop ) // I hate you SPP.
	end
	GM:AddConCommand( "inc_spawn", "SpawnProp" )
	
	function GM:SpawnEntity( ply, _, args )
		if ( !self:IsBuild() ) then return end
		
		local entity = args[ 1 ]
		
		if ( !entities[ entity ] ) then return end
		local info = entities[ entity ]
		
		if ( !self:SpendCredits( ply, info.Cost ) ) then return end
		
		local freeze = true
		if ( info.FreezeOnFight != nil ) then freeze = info.FreezeOnFight end
		
		local trace = util.QuickTrace( ply:GetShootPos(), ply:GetAimVector() * 8192, ply )
		local angle = ply:EyeAngles()
			angle.p, angle.y, angle.r = 0, angle.y + 180, 0
		local ent = ents.Create( entity )
			ent:SetPos( trace.HitPos + ( trace.HitNormal * ( info.AddNormal or 16 ) ) + ( info.AddV or Vector( 0, 0, 0 ) ) )
			ent.Player = ply:UniqueID()
			ent.CanPhysgunPickup = true
			ent.Repairable = info.Repairable
			ent.ShouldTakeDamage = info.ShouldTakeDamage
			ent.Cost = info.Cost
			ent.BlowUp = info.BlowUp
			ent.FreezeOnFight = freeze
		ent:Spawn()
		
		if ( info.Health ) then
			ent:SetPropHealth( info.Health )
			ent:SetPropMaxHealth( info.Health )
		end
		
		if ( !info.SetAngles ) then
			ent:SetAngles( angle )
		else
			info.SetAngles( ent, ply, trace )
		end
		
		// Prop protection, bitches?
		hook.Call( "PlayerSpawnedSENT", self, ply, ent )
	end
	GM:AddConCommand( "inc_spawnentity", "SpawnEntity" )
	
	function GM:OnPhysgunReload() end
	function GM:RepairProp( weap, ply )
		if ( !self:IsBuild() ) then return end
		local trace = util.QuickTrace( ply:GetShootPos(), ply:GetAimVector() * 8192, ply )
		if ( trace.Entity:IsValid() && trace.Entity.Repairable ) then
			local healthpercent = self:GetPropHealthPercent( trace.Entity )
			if ( healthpercent != 1 ) then
				local cost = ( 1 - healthpercent ) * ( trace.Entity.Cost or 0 ) * 0.5
				if ( self:SpendCredits( ply, cost ) ) then
					self:SetPropHealth( trace.Entity, self:GetPropMaxHealth( trace.Entity ) )
				else
					local percent = self:GetCredits( ply ) / cost
					self:SetPropHealth( trace.Entity, self:GetPropHealth( trace.Entity ) + ( percent * self:GetPropMaxHealth( trace.Entity ) ) )
					self:SpendCredits( ply, self:GetCredits( ply ) )
				end
			end
		end
	end
	GM:AddHook( "OnPhysgunReload", "RepairProp" )
	
	function GM:RemoveProp( ply )
		if ( !self:IsBuild() ) then return end
		local trace = util.QuickTrace( ply:GetShootPos(), ply:GetAimVector() * 8192, ply )
		if ( trace.Entity:IsValid() && trace.Entity.Player == ply:UniqueID() ) then
			local percent = self:GetPropHealthPercent( trace.Entity )
			if ( percent == -1 ) then percent = 1 end
			self:GiveCredits( ply, ( trace.Entity.Cost or 0 ) * percent )
			trace.Entity:Remove()
		end
	end
	GM:AddConCommand( "undo", "RemoveProp" )
	
	// Freeze stuff when fight round starts.
	function GM:FreezeOnFight()
		if ( !self:IsFight() ) then return end
		
		for _, e in pairs( ents.GetAll() ) do
			if ( e.FreezeOnFight ) then
				local phys = e:GetPhysicsObject()
				if ( phys:IsValid() ) then
					phys:EnableMotion( false )
				end
			end
		end
	end
	GM:AddHook( "RoundChanged", "FreezeOnFight" )
	
end // End of SERVER.

if ( CLIENT ) then

local SFTR30 = Font( "SF TransRobotics", 30 )

local PANEL = {}
function PANEL:Init()
	self.Categories = {}
	self.CategoryOrder = {}
	self.Category = ""
end
function PANEL:PerformLayout()
	local w, h = ScrW() * 0.5, 0
	local padding = 20
	local padding2 = padding * 2
	local iconWidth = 64
	local iconSpacing = 3
	local iconSize = iconWidth + iconSpacing
	
	// Remove the padding from the width.
	w = w - padding2
	h = padding2
	local x, y = padding, padding
	
	for _, category in pairs( self.CategoryOrder ) do
	if ( self.Categories[ category ] ) then
		local info = self.Categories[ category ]
		info.Label:SetPos( x, y )
		info.Label:SetSize( w, 20 )
		// Add indent and shift below label.
		x, y = x + 20, y + info.Label:GetTall() + 10
		h = h + info.Label:GetTall() + 5
		
		local maxX = math.floor( w / iconSize ) - 1
		for i, icon in pairs( info.Icons ) do
			local xpos, ypos = ( ( i - 1 ) % maxX ), math.floor( ( i - 1 ) / maxX )
			icon:SetPos( x + ( xpos * iconSize ), y + ( ypos * iconSize ) )
			icon:SetSize( iconWidth )
		end
		
		local addY = ( math.ceil( #info.Icons / maxX ) * iconSize ) + 5
		y = y + addY
		h = h + addY
		
		// Remove indent.
		x = x - 20
	end
	end
	
	self:SetSize( w, h )
	self:SetPos( ( ScrW() - w ) / 2, ( ScrH() - h ) / 2 )
end
function PANEL:SetCategory( name )
	self.Category = name
	if ( !self.Categories[ name ] ) then
		local label = vgui.Create( "DLabel", self )
			label:SetText( name )
			label:SetFont( SFTR30 )
			label:SetSize( 100, 30 )
			label:SetTextColor( HUD_TEXT_COLOUR )
		self.Categories[ name ] = { Label = label, Icons = {} }
	end
	if ( !table.HasValue( self.CategoryOrder, name ) ) then
		self.CategoryOrder[ #self.CategoryOrder + 1 ] = name
	end
end
function PANEL:AddIcon( path, command, tooltip )
	if ( !self.Categories[ self.Category ] ) then return end
	
	local image = vgui.Create( "SpawnIcon", self )
		image.Model = path
		image:SetModel( path, 0 )
		image:SetTooltip( tooltip or "" )
	
		function image:DoClick()
			surface.PlaySound( "ui/buttonclickrelease.wav" )
			RunConsoleCommand( unpack( command ) )
		end
	
	local icons = self.Categories[ self.Category ].Icons
	icons[ #icons + 1 ] = image
end
function PANEL:Paint()
	local w, h = self:GetSize()
	
	surface.SetDrawColor( 40, 75, 125, 200 )
	surface.DrawRect( 0, 0, w, h )
	surface.SetDrawColor( 30, 55, 90, 200 )
	surface.DrawOutlinedRect( 0, 0, w, h )
end
vgui.Register( "incursion.spawnmenu", PANEL )

function GM:CreateSpawnMenu()
	self.SpawnMenu = vgui.Create( "incursion.spawnmenu" )
	self.SpawnMenu:MakePopup()
	self.SpawnMenu:SetVisible( false )
	
	for _, category in pairs( categories ) do
		self.SpawnMenu:SetCategory( category[ 1 ] )
		pcall( category[ 2 ], self.SpawnMenu )
	end
	
	self.SpawnMenu:InvalidateLayout()
end
GM:AddHook( "Initialize", "CreateSpawnMenu" )
if ( GAMEMODE ) then GM:CreateSpawnMenu() end

local x, y
function GM:SetSpawnMenu( bool )
	if ( !self:IsBuild() && bool == true ) then return end
	if ( !self.SpawnMenu ) then printd( "No spawn menu!" ) return end
	
	if ( !bool ) then
		x, y = gui.MousePos()
	elseif ( x && y ) then
		gui.SetMousePos( x, y )
		x, y = nil, nil
	end
	
	self.SpawnMenu:SetVisible( bool )
end
concommand.Add( "+menu", function() GAMEMODE:SetSpawnMenu( true ) end )
concommand.Add( "-menu", function() GAMEMODE:SetSpawnMenu( false ) end )

function GM:CloseSpawnMenuFight()
	GAMEMODE:SetSpawnMenu( false )
end
GM:AddHook( "RoundChanged", "CloseSpawnMenuFight" )

end // End of CLIENT.